package org.zjt.design.pattern;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.util.Objects;

import static java.lang.System.out;

/**
 * @author <a href="juntao.zhang@qq.com">juntao.zhang</a>
 * @Description: 原型模式，返回重复克隆的信息。【注意浅拷贝和深拷贝的问题】
 * @Package org.zjt.design.pattern
 * @date 2018/5/8 15:32
 *
 * 原型模式（Prototype Pattern）是用于创建重复的对象，同时又能保证性能。
 * 这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。 返回一个对象的克隆


    这种模式是实现了一个原型接口，该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时，则采用这种模式。
    例如，一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象，在下一个请求时返回它的克隆，在需要的时候更新数据库，以此来减少数据库调用。
 */
public class PrototypeTest {

    public static void main(String[] args) {
        PrototypeUser user = new PrototypeUser();
        user.setAge(12);
        user.setName("zhangsan");
        user.setAddr(new Addr("700000","西安"));
        out.println(user);
        PrototypeUser clone = user.clone();
        clone.setName("zhangsan-clone");
        out.println(clone);
        out.println(user);
        out.println(clone.getAddr() == user.getAddr());
    }

}

/**
 *
 * clone 默认是浅拷贝。
 *      只拷贝当前类中的基本类型变量。
 *
 * clone 深拷贝：
 *      需要在clone 方法中调用非基本类型变量的clone方法。（该引用方法必须实现cloneable中的clone方法）
 *
 */
@Data
@ToString
class PrototypeUser implements Cloneable{

    private String name;
    private Integer age;
    private Addr addr;

    @Override
    public PrototypeUser clone(){
        PrototypeUser prototypeClass = null;
        try {
            prototypeClass = (PrototypeUser)super.clone();
            if (Objects.nonNull(addr))
                prototypeClass.addr = addr.clone();
        } catch (CloneNotSupportedException e) {
        }
        return prototypeClass;
    }
}

@Data
@AllArgsConstructor
class Addr implements Cloneable{
    private String code;
    private String name;

    @Override
    public Addr clone() throws CloneNotSupportedException {
        return (Addr)super.clone();
    }
}